package org.dizena.common.utils;

import jakarta.servlet.http.HttpServletRequest;
import org.dizena.common.base.enums.EnumHeaderKey;
import org.dizena.common.base.struct.TransmittableThreadLocalMap;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.*;

public class ReqUtil {
    public static Map<String, String> getHeaderMap(HttpServletRequest request) {
        Map<String, String> header = new LinkedHashMap<>();
        Enumeration<String> names = request.getHeaderNames();
        while (names.hasMoreElements()) {
            String key = names.nextElement();
            header.put(key, request.getHeader(key));
        }
        return header;
    }

    public static Map<String, String> getHeaderMap() {
        HttpServletRequest request = getRequest();
        if (request != null) {
            return getHeaderMap(request);
        }
        return new LinkedHashMap<>();
    }

    public static Map<String, String> getTraceHeaderMap() {
        Map<String, String> header = getHeaderMap();
        HttpServletRequest request = getRequest();
        if (!header.containsKey(EnumHeaderKey.TRACE_ID.getKey()) && request != null) {
            Object reqId = request.getAttribute(EnumHeaderKey.TRACE_ID.getKey());
            if (reqId != null) {
                header.put(EnumHeaderKey.TRACE_ID.getKey(), String.valueOf(reqId));
            }
        }
        return header;
    }

    public static Map<String, String> getAllHeaderMap() {
        Map<String, String> header = getTraceHeaderMap();
        if (header.isEmpty()) {
            header = TransmittableThreadLocalMap.get();
        }
        return header;
    }

    public static Map<String, String> filterAllHeaderMap() {
        Map<String, String> data = new HashMap<>();
        Map<String, String> header = getAllHeaderMap();

        EnumHeaderKey.keys().forEach(k -> {
            String v = header.get(k);
            if (v != null && v.length() > 0) {
                data.put(k, v);
            }
        });

        return data;
    }

    public static Map<String, String> filterAllHeaderMap(List<String> keys) {
        Map<String, String> data = filterAllHeaderMap();
        Map<String, String> header = getAllHeaderMap();
        if (keys != null && keys.size() > 0) {
            keys.forEach(k -> {
                String v = header.get(k);
                if (v != null && v.length() > 0) {
                    data.put(k, v);
                }
            });
        }
        return data;
    }

    public static Map<String, String> getHeaderMap(Map<String, Collection<String>> headers) {
        Map<String, String> output = new LinkedHashMap<>();
        for (String key : headers.keySet()) {
            output.put(key, String.join(";", headers.get(key)));
        }
        return output;
    }

    public static String getHeader(String key) {
        HttpServletRequest request = getRequest();
        if (request != null) {
            return request.getHeader(key);
        }
        return null;
    }

    public static String getAttribute(String key) {
        HttpServletRequest request = getRequest();
        if (request != null) {
            return String.valueOf(request.getAttribute(key));
        }
        return null;
    }

    public static String getTrace(String key) {
        String value = getHeader(key);
        return null == value ? getAttribute(key) : value;
    }

    public static String getTrace() {
        return getAllHeaderMap().get(EnumHeaderKey.TRACE_ID.getKey());
    }

    public static HttpServletRequest getRequest() {
        RequestAttributes ras = RequestContextHolder.getRequestAttributes();
        if (ras != null && ras instanceof ServletRequestAttributes) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) ras;
            return attributes.getRequest();
        }
        return null;
    }

    private static final String UNKNOWN = "unknown";

    public static String getRequestIP(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
